#!/bin/bash

# ==============================================================================
# Script Name: images_pull_push.sh
# Description: 用于将 Docker 镜像从源仓库拉取并修改tag推动到目标 Harbor 仓库
# Author:       lldhsds
# Version:      1.0
# Date:         2024-11-20
# Usage:        详见 help 信息
# Dependencies: linux，docker, curl
# Notes:
#   1. Harbor 仓库必须支持 HTTPS 协议，并且运行脚本的终端已配置证书和仓库受信任。如果需要http协议，需要修改脚本中url中的请求协议。
#   2. 镜像列表文件中每行记录一个镜像，格式为 'repo/project/image:tag'。
# ==============================================================================

# 显示帮助信息
usage() {
    echo "Usage: "
    echo 
    echo "用法: $0 [-f <镜像列表文件>] [-d <目标镜像仓库>] [-u <目标仓库用户名>] [-p <目标仓库密码>]"
    echo
    echo "Description:"
    echo " -f <镜像列表文件>            : 镜像列表文件路径，例如 images.txt，注意路径"
    echo " -d <目标镜像仓库>            : 目标镜像仓库地址，例如 harbor.example.com。"
    echo " -u <目标仓库用户名>          : 目标仓库用户名，例如 admin，用户需要由创建harbor项目的权限。"
    echo " -p <目标仓库密码>            : 目标仓库密码，例如Harbor12345"
    echo
    echo "Example:"
    echo "# 1. 从 images.txt 列表文件中的镜像下载并推送到 harbor.example.com 仓库。"
    echo " $0 -f images.txt -d harbor.example.com -u admin -p Harbor12345"
    echo 
    echo "限制条件："
    echo " 1. harbor仓库为https协议，并且运行脚本的终端已配置证书和仓库受信任。 "
    echo " 2. 镜像列表文件中每行记录一个镜像: "
    echo " 例如'docker.io/bitnami/mysql:5.7.43'，由'repo/project/image:tag'组成。如果从dokcerhub拉取，不能省略repo和project，对于大部分镜像docker.io和library为默认的仓库和项目名称，文件中需要补全。"
    exit 1
}

# 解析参数
while getopts ":f:d:u:p:" opt; do
    case ${opt} in
        f) IMAGE_LIST="$OPTARG";;
        d) TARGET_REPO="$OPTARG";;
        u) HARBOR_USERNAME="$OPTARG";;
        p) HARBOR_PASSWORD="$OPTARG";;
        \? )usage;;
    esac
done

# 移除已解析的参数
shift $((OPTIND - 1))

# 检查参数数量
if [ -z "$IMAGE_LIST" ] || [ -z "$TARGET_REPO" ] || [ -z "$HARBOR_USERNAME" ] || [ -z "$HARBOR_PASSWORD" ]; then
    usage
fi

# 检查镜像列表文件是否存在
if [ ! -f "$IMAGE_LIST" ]; then
    echo "镜像列表文件 $IMAGE_LIST 不存在。"
    exit 1
fi

# 函数：检查并创建 Harbor 项目
create_harbor_project() {
    PROJECT_NAME="$1"
    LIST_PRO_API="https://$TARGET_REPO/api/v2.0/projects/$PROJECT_NAME"
    echo $LIST_PRO_API

    # 检查项目是否存在
    RESPONSE=$(curl --noproxy -s -k -w '%{http_code}\n' -o /dev/null -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" -X 'GET' "$LIST_PRO_API" -H 'accept: application/json' -H 'X-Is-Resource-Name: false')

    if [ "$RESPONSE" -eq 404 ]; then
        echo "项目 ${PROJECT_NAME} 不存在，正在创建..."
        # echo $TARGET_REPO
        # 创建harbor项目的请求体，创建公开的项目
        json_playload="{\"project_name\": \"$PROJECT_NAME\",\"public\": true}"
        curl --noproxy -s -k -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" -X 'POST' "https://$TARGET_REPO/api/v2.0/projects" -H 'accept: application/json' -H 'Content-Type: application/json' -d "$json_playload"
        echo "项目 ${PROJECT_NAME} 创建完成。"
    else
        echo "项目 ${PROJECT_NAME} 已存在。"
        echo $TARGET_REPO   
    fi
}

# 登录 Harbor 仓库
# echo "登录 Harbor 仓库: $TARGET_REPO"
# echo "HARBOR_USERNAME: $HARBOR_USERNAME"
# echo "HARBOR_PASSWORD: $HARBOR_PASSWORD"
# echo "TARGET_REPO: $TARGET_REPO"
docker login -u "$HARBOR_USERNAME" -p "$HARBOR_PASSWORD" "$TARGET_REPO"

# 循环处理镜像列表
while IFS= read -r IMAGE; do
    # 获取目标项目名称
    IMAGE_PROJECT=$(echo "${IMAGE}" | cut -d':' -f1 | cut -d'/' -f2)
    IMAGE_NAME=$(echo "${IMAGE}" | cut -d'/' -f3)

    # 检查并创建 Harbor 项目
    create_harbor_project "${IMAGE_PROJECT}"

    # 拉取源镜像
    echo "拉取镜像: ${IMAGE}"
    docker pull "${IMAGE}"
   
    # 标记镜像为目标镜像
    TARGET_IMAGE="${TARGET_REPO}/${IMAGE_PROJECT}/${IMAGE_NAME}"
    echo "标记镜像: ${TARGET_IMAGE}"
    docker tag "${IMAGE}" "${TARGET_IMAGE}"

    # 推送到目标镜像仓库
    echo "推送镜像: ${TARGET_IMAGE}"
    docker push "${TARGET_IMAGE}"

done < "$IMAGE_LIST"

echo "所有镜像处理完成。"
